package bancosys.tec.rtm.diagnostician.rmi;

import java.io.OutputStream;

import bancosys.tec.rtm.RtmException;
import bancosys.tec.rtm.diagnostician.DiagnosticianCase;
import bancosys.tec.rtm.diagnostician.exception.DiagnosticianException;
import bancosys.tec.rtm.diagnostician.report.DiagnosticianReportGenerator;

/**
 * Componente que inicializa e gerencia as necessidades da parte RMI do Diagnosticador.
 * 
 * @author Evaristo
 * @version $Id:$ <b>Created on: </b> 04/06/2007
 */
public class DiagnosticianRMI {

    private DiagnosticianRMIHome diagnosticianRMIHome;

    private String ip;

    private int port;

    private String name;

    private String diagnosticianCaseImplClassName;

    /**
     * Inicializa o DiagnosticianRMI.
     * 
     * @throws Exception e
     */
    public void initializeDiagnosticianRMI() throws Exception {
        this.diagnosticianRMIHome = new DiagnosticianRMIHome();

        DiagnosticianCase diagnosticianCase = (DiagnosticianCase) this.instantiationClassForName(this.diagnosticianCaseImplClassName);

        this.diagnosticianRMIHome.initializeDiagnosticianRMIHome(diagnosticianCase, this.getIp(), this.getPort(), this.getName());
    }

    /**
     * Finaliza o DiagnosticianRMI.
     */
    public void finalizeDiagnosticianRMI() {
        this.diagnosticianRMIHome.finalizeDiagnosticianRMIHome(this.getIp(), this.getPort(), this.getName());
        this.diagnosticianRMIHome = null;
    }

    /**
     * Retorna DiagnosticianRMIService local.
     * 
     * @return DiagnosticianRMIService
     */
    public DiagnosticianRMIService getLocalDiagnosticianRMIService() {
        return this.diagnosticianRMIHome.getDiagnosticianLocalRMIService();
    }

    /**
     * Retorna DiagnosticianRMIService do Ip passado no parâmetro.
     * 
     * @param ipAddress o ip
     * @return DiagnosticianRMIService
     * @throws DiagnosticianException e
     */
    public DiagnosticianRMIService getDiagnosticianRMIService(String ipAddress) throws DiagnosticianException {
        return this.diagnosticianRMIHome.getDiagnosticianRMIService(ipAddress, this.port, this.name);
    }

    /**
     * Gera o report do diagnosticador da maquina local.
     * 
     * @param outputStream {@link OutputStream} saida do diagnostician.
     * @param diagnosticianReportGenerator {@link DiagnosticianReportGenerator}
     * @throws DiagnosticianException e
     */
    public void generateLocalReport(OutputStream outputStream, DiagnosticianReportGenerator diagnosticianReportGenerator)
            throws DiagnosticianException {
        DiagnosticianRMIService diagnosticianRMIService = this.diagnosticianRMIHome.getDiagnosticianLocalRMIService();
        try {
            byte[] report = diagnosticianRMIService.generateReport(diagnosticianReportGenerator.getClass().getName());
            outputStream.write(report);
        } catch (Throwable e) {
            throw new DiagnosticianException("Erro ao gerar o report do diagnosticador. URL: "
                    + this.diagnosticianRMIHome.getURL(this.ip, this.port, this.name), e);
        }
    }

    /**
     * Gera o report do diagnosticador.
     * 
     * @param outputStream saida
     * @param diagnosticianReportGenerator gerador
     * @param ipAddress endereco ip
     * @throws DiagnosticianException e
     */
    public void generateReport(OutputStream outputStream, DiagnosticianReportGenerator diagnosticianReportGenerator, String ipAddress)
            throws DiagnosticianException {
        DiagnosticianRMIService diagnosticianRMIService =
                this.diagnosticianRMIHome.getDiagnosticianRMIService(ipAddress, this.getPort(), this.getName());
        try {
            byte[] report = diagnosticianRMIService.generateReport(diagnosticianReportGenerator.getClass().getName());
            outputStream.write(report);
        } catch (Throwable e) {
            throw new DiagnosticianException("Erro ao gerar o report do diagnosticador. URL: "
                    + this.diagnosticianRMIHome.getURL(ipAddress, this.getPort(), this.getName()), e);
        }
    }

    /**
     * Retorna a classname da implementação de DiagnosticianCase.
     * 
     * @return String
     */
    public String getDiagnosticianCaseImplClassName() {
        return this.diagnosticianCaseImplClassName;
    }

    /**
     * Seta a classname da implementação de DiagnosticianCase.
     * 
     * @param diagnosticianCaseImplClassName String
     */
    public void setDiagnosticianCaseImplClassName(String diagnosticianCaseImplClassName) {
        this.diagnosticianCaseImplClassName = diagnosticianCaseImplClassName;
    }

    /**
     * Retorna Ip.
     * 
     * @return String
     */
    public String getIp() {
        return this.ip;
    }

    /**
     * Seta o ip.
     * 
     * @param ip String
     */
    public void setIp(String ip) {
        this.ip = ip;
    }

    /**
     * Retorna Porta que está sendo usada para RMI.
     * 
     * @return int
     */
    public int getPort() {
        return this.port;
    }

    /**
     * Seta porta.
     * 
     * @param port int
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * Retorna o nome dos serviço.
     * 
     * @return String
     */
    public String getName() {
        return this.name;
    }

    /**
     * Seta o nome do serviço.
     * 
     * @param name o nome do servico
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Retorna um instancia da Classe de nome passado no parametro.
     * 
     * @param className String
     * @return Object
     * @throws RtmException e
     */
    private Object instantiationClassForName(String className) throws RtmException {
        try {
            return Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            throw new RtmException("Erro ao instanciar a classe \"" + className + "\".", e);
        } catch (IllegalAccessException e) {
            throw new RtmException("Erro ao inicializar a classe \"" + className + "\".", e);
        } catch (ClassNotFoundException e) {
            throw new RtmException("Erro, a classe \"" + className + "\" não foi localizada no Classpath.", e);
        } catch (Throwable e) {
            throw new RtmException("Erro ao tentar instanciar a classe \"" + className + "\".", e);
        }
    }
}